package com.wwcom.darteagle.model;

import java.util.ArrayList;
import java.util.List;

public class Match {
	protected List<MatchPlayer> matchPlayers;
	protected MatchInfo matchInfo;
	protected int setInd;
	
	protected MatchPlayer currentPlayer;
	protected MatchPlayer legStartPlayer;
	protected MatchPlayer setStartPlayer;

	private List<DartStats> playerStats;	
	
	public Match() {
		initialiseSelf();
	}
	
	public Match(MatchInfo matchInfo) {
		initialiseSelf();
		this.matchInfo= matchInfo;
		this.matchPlayers= matchInfo.getMatchPlayers();
	}	
	
	protected void initialiseSelf() {
		matchPlayers= new ArrayList<MatchPlayer>();
		matchInfo= new MatchInfo();
		currentPlayer= null;
		legStartPlayer= null;
		setInd= -1;
	}

	//accessors
	public void setId(long id) {
		matchInfo.setId(id);
	}
	
	public long getId() {
		return matchInfo.getId();
	}
	
	public void setDate(long date) {
		matchInfo.setDate(date);
	}
	
	public long getDate() {
		return matchInfo.getDate();
	}

	public void setSetInd(int setInd) {
		this.setInd= setInd;
	}
	
	public MatchInfo getMatchInfo() {
		return matchInfo;
	}
	
	public boolean isDoubleIn() {
		return matchInfo.isDoubleIn();
	}

	public void setDoubleIn(boolean doubleIn) {
		matchInfo.setDoubleIn(doubleIn);
	}

	public boolean isDoubleOut() {
		return matchInfo.isDoubleOut();
	}

	public void setDoubleOut(boolean doubleOut) {
		matchInfo.setDoubleOut(doubleOut);
	}

	public boolean isTrebleIn() {
		return matchInfo.isTrebleIn();
	}

	public void setTrebleIn(boolean trebleIn) {
		matchInfo.setTrebleIn(trebleIn);
	}

	public boolean isTrebleOut() {
		return matchInfo.isTrebleOut();
	}

	public void setTrebleOut(boolean trebleOut) {
		matchInfo.setTrebleOut(trebleOut);
	}

	public int getNumLegs() {
		return matchInfo.getNumLegs();
	}

	public void setNumLegs(int numLegs) {
		matchInfo.setNumLegs(numLegs);
	}

	public int getNumSets() {
		return matchInfo.getNumSets();
	}

	public void setNumSets(int numSets) {
		matchInfo.setNumSets(numSets);
	}

	public int getLegTarget() {
		return matchInfo.getLegTarget();
	}

	public void setLegTarget(int legTarget) {
		matchInfo.setLegTarget(legTarget);
	}

	public MatchPlayer getCurrentPlayer() {
		return currentPlayer;
	}
	
	public MatchPlayer getLastPlayer() {
		//move on to next player
		int currentInd= matchPlayers.indexOf(currentPlayer);
		if (currentInd == 0)
			return matchPlayers.get(matchPlayers.size()-1);
		else
			return matchPlayers.get(currentInd-1);
	}

	public MatchPlayer getLegStartPlayer() {
		return legStartPlayer;
	}

	public int getLegNumber() {
		throw new RuntimeException("Match::getLegNumber - unimplmented in base class");
	}
	
	public int getSetNumber() {
		throw new RuntimeException("Match::getSetNumber - unimplmented in base class");
	}

	//player management	
	public List<MatchPlayer> getMatchPlayers() {
		return matchPlayers;		
	}
		
	//messages and display	
	public List< List<VisitScore> > getLegHistory() {
		throw new RuntimeException("Match::getLegHistory - unimplemented in base class");
	}

	public List<VisitScore> getPlayerCurrentScores() {
		throw new RuntimeException("Match::getPlayerCurrentScores - unimplemented in base class");
	}
	
	public boolean isCurrentPlayer(MatchPlayer matchPlayer) {
		return currentPlayer.equals(matchPlayer);
	}
	
	public boolean isLegStartPlayer(MatchPlayer matchPlayer) {
		return legStartPlayer.equals(matchPlayer);
	}

	//playing logic
	public void startPlaying() {
		if (matchPlayers == null || matchPlayers.size() == 0)
			throw new RuntimeException("Match::startPlaying - no players in list");
		
		currentPlayer= matchPlayers.get(0);
		legStartPlayer= matchPlayers.get(0);
		setStartPlayer= matchPlayers.get(0);
		
		//make a list of stats, one for each player
		playerStats= new ArrayList<DartStats>(matchPlayers.size());			
		for (MatchPlayer mp : matchPlayers) {
			playerStats.add(new DartStats(matchInfo,mp,-1,-1));
		}
		
	}

	protected void startPlaying(MatchPlayer currentPlayer) {
		if (matchPlayers.size() == 0)
			throw new RuntimeException("Match::startPlaying - no players in list");
		
		this.currentPlayer= currentPlayer;
		legStartPlayer= currentPlayer;
		setStartPlayer= currentPlayer;

		playerStats= new ArrayList<DartStats>(matchPlayers.size());			
		for (MatchPlayer mp : matchPlayers) {
			playerStats.add(new DartStats(matchInfo,mp,-1,-1));
		}

	}
	
	public void nextPlayer() {
		//move on to next player
		int currentInd= matchPlayers.indexOf(currentPlayer);
		if (currentInd == matchPlayers.size()-1)
			currentPlayer= matchPlayers.get(0);
		else
			currentPlayer= matchPlayers.get(currentInd+1);
		
	}	

	public void nextLeg() {
		//move on to next player
		legStartPlayer= getNextLegStartPlayer();
		currentPlayer= legStartPlayer;
	}
	
	public List<Leg> getLegs() {
		throw new RuntimeException("Match::getLegs - unimplemented in base class");		
	}
	
	public void nextSet() {
		//move on to next player
		setStartPlayer= getNextSetStartPlayer();
		currentPlayer= setStartPlayer;
		legStartPlayer= currentPlayer;
	}	
	
	public List<Set> getSets() {
		throw new RuntimeException("Match::getSets - unimplemented in base class");		
	}

	public VisitScore updateCurrentPlayerScore( Score score ) {
		throw new RuntimeException("Match::updateCurrentPlayerScore - unimplemented in base class");
	}

	public void finalisePlayerScore(MatchPlayer matchPlayer, int visitInd) {
		throw new RuntimeException("Match::finalisePlayerScore - unimplemented in base class");
	}

	public void unFinalisePlayerScore(MatchPlayer matchPlayer, int visitInd) {
		throw new RuntimeException("Match::unFinalisePlayerScore - unimplemented in base class");
	}

	public VisitScore updatePlayerScore(MatchPlayer matchPlayer, int visitInd, Score score ) {
		throw new RuntimeException("Match::updatePlayerScore - unimplemented in base class");
	}
	
	public VisitScore getCurrentPlayerScore() {
		throw new RuntimeException("Match::getCurrentPlayerScore - unimplemented in base class");		
	}
			
	public VisitScore getVisitScore(MatchPlayer matchPlayer, int visitInd) {
		throw new RuntimeException("Match::getVisitScore - unimplemented in base class");		
	}

	public MatchPlayer getLegWinner() {
		throw new RuntimeException("Match::getLegWinner - unimplemented in base class");		
	}
	
	public MatchPlayer getSetWinner() {
		throw new RuntimeException("Match::getSetWinner - unimplemented in base class");		
	}

	public MatchPlayer getNextLegStartPlayer() {
		MatchPlayer localLegStartPlayer= legStartPlayer;
		//if loser starts, then get the winning player and start the next player in the list
		if (matchInfo.isLoserStarts()) {
			localLegStartPlayer= getLegWinner();
		}
		int currentInd= matchPlayers.indexOf(localLegStartPlayer);
		if (currentInd == matchPlayers.size()-1)
			return matchPlayers.get(0);
		else
			return matchPlayers.get(currentInd+1);
	}	
	
	public MatchPlayer getNextSetStartPlayer() {
		MatchPlayer localSetStartPlayer= setStartPlayer;
		//if loser starts, then get the winning player and start the next player in the list
		if (matchInfo.isLoserStarts()) {
			localSetStartPlayer= getSetWinner();
		}
		int currentInd= matchPlayers.indexOf(localSetStartPlayer);
		if (currentInd == matchPlayers.size()-1)
			return matchPlayers.get(0);
		else
			return matchPlayers.get(currentInd+1);
	}	
	
	public boolean isLegComplete() {
		throw new RuntimeException("Match::isLegComplete - unimplemented in base class");
	}

	public boolean isSetComplete() {
		throw new RuntimeException("Match::isSetComplete - unimplemented in base class");
	}

	public boolean isMatchComplete() {
		throw new RuntimeException("Match::isSetComplete - unimplemented in base class");
	}
	
	//statisitcs
	public List<DartStats> getPlayerStats() {
		return playerStats;
	}

	public void setPlayerStats(List<DartStats> ds) {
		playerStats= ds;
	}

	public List<DartStats> getPlayerStatsLeg(int setInd, int legInd) {
		throw new RuntimeException("Match::getPlayerStatsCurrentLeg - unimplemented in base class");
	}
	
	public List<DartStats> getPlayerStatsSet(int setInd) {
		throw new RuntimeException("Match::getPlayerStatsCurrentSet - unimplemented in base class");
	}
	
	protected void addPlayerStatistics(MatchPlayer matchPlayer, VisitScore visitScore) {
		for (DartStats ds : playerStats) {
			if (ds.getMatchPlayer()==matchPlayer) {
				ds.addDartStats(visitScore);
				break;
			}
		}
	}

	protected List<VisitScore> getPlayerMatchHistory(MatchPlayer matchPlayer) {
		throw new RuntimeException("Match::getPlayerMatchHistory - unimplemented in base class");
	}

	protected void updatePlayerStatistics(MatchPlayer matchPlayer) {
		List<VisitScore> pmh= getPlayerMatchHistory(matchPlayer);
		for (int i= 0; i < playerStats.size(); i++) {			
			if (playerStats.get(i).getMatchPlayer().equals(matchPlayer)) {
				DartStats ds= new DartStats(matchInfo,matchPlayer,setInd,-1);
				for (VisitScore vs : pmh) {
					if (vs.isFinalised()) {
						ds.addDartStats(vs);
					}
				}
				playerStats.set(i, ds);
				break;
			}
		}
	}
	
	//database serialisation
	public List<VisitScore> getAllVisitScoresInVisitOrder() {		
		throw new RuntimeException("Match::getAllVisitScores - unimplemented in base class");
	}
	
}
